//------------------------------------------------------------
//  Filename: vga_driver.v
//   
//  Author  : wlduan@gmail.com
//  Revise  : 2016-10-08 10:54
//  Description: 
//   
//  Copyright (C) 2014, YRBD, Inc. 					      
//  All Rights Reserved.                                       
//-------------------------------------------------------------
//
`timescale 1ns/1ps
 
module VGA_DRIVER ( 
     // Users to add ports here
     input wire clk_vga,  
     input wire rst    ,
     
     output reg [7:0]   vga_R,
     output reg [7:0]   vga_G,
     output reg [7:0]   vga_B,
     output wire        vga_pclk,
     output reg         vga_h_sync,  
     output reg         vga_v_sync,
     output reg         vga_de,
     // User ports fifo
     input  wire        mm_disp_en,   
     input  wire        mm_menu_en,   
     input  wire        mm_bar_hide,   
     output wire        disp_rd_clk,
     output wire        disp_rd_en,
     input  wire        disp_empty,
     input  wire [7:0]  disp_graym,
     input  wire [7:0]  menu_alpha,  
     input  wire [32:0] disp_dout,
     input  wire [32:0] menu_dout
);
//--------------------------------------------------------

`ifdef SIMULATION
localparam HL_PIXS  = 9 ;// 60us
localparam VL_LINES = 2 ;// 0.3us
localparam VLINES   = 52;//
localparam HPIXELS  = 80;//
localparam HBP      = 14;//
localparam HFP      = 78;//
localparam VBP      = 3 ;//
localparam VFP      = 51;//
`else
localparam VLINES   = 525; //vga_disp_hvcnt[15:0] ; //行数=521
localparam HPIXELS  = 800; //vga_disp_hvcnt[31:16]; //行像素点=800
localparam HL_PIXS  = 4;   //vga_disp_hvcnt[31:16]; //行像素点=800
localparam VL_LINES = 3;   //vga_disp_hvcnt[31:16]; //行像素点=800
localparam HBP      = 46;  //vga_disp_hconf[15:0] ; //行显示后沿=144(96+48)
localparam HFP      = 686; //vga_disp_hconf[31:16]; //行显示前沿=784（96+48+640）
localparam VBP      = 34;  //vga_disp_vconf[15:0] ; //场显示后沿=36(2+33)
localparam VFP      = 514; //vga_disp_vconf[31:16]; //场显示前沿=511（2+33
`endif
//--------------------------------------------------------
reg [9:0] h_counter;
reg [9:0] v_counter;
//锟斤拷同锟斤拷锟脚号硷拷锟斤拷锟斤拷
//--------------------------------------------------------
always @(posedge clk_vga,posedge rst) begin
    if(rst)begin 
        h_counter<=0;//锟斤拷锟斤拷锟斤拷锟斤拷位
    end 
    else if(h_counter==HPIXELS) begin
        h_counter<=0;//锟斤拷锟斤拷锟斤拷锟斤拷位
    end
    else begin
        h_counter<=h_counter+1;
    end
end
//--------------------------------------------------------
reg vs_enable;
always@(posedge clk_vga ) vs_enable<=(h_counter==HPIXELS)?1:0; 
//--------------------------------------------------------
//锟斤拷同锟斤拷锟脚号硷拷锟斤拷锟斤拷
always @(posedge clk_vga,posedge rst) begin
    if(rst)begin 
        v_counter<=0;//锟斤拷锟斤拷锟斤拷锟斤拷位
    end 
    else if(vs_enable==1) begin
        v_counter<=(v_counter==VLINES)?0:(v_counter+1);
    end 
end
//锟斤拷v_counter为0锟斤拷1时锟斤拷锟斤拷同锟斤拷锟斤拷锟斤拷为锟酵碉拷平
//锟斤拷h_counter为0--127时锟斤拷锟斤拷同锟斤拷锟斤拷锟斤拷为锟酵碉拷平
reg h_sync;
reg v_sync;
always@(posedge clk_vga) h_sync <= (h_counter<HL_PIXS)?0:1;
always@(posedge clk_vga) v_sync <= (v_counter<VL_LINES)?0:1;
//--------------------------------------------------------
assign disp_rd_clk   = clk_vga;
wire   data_rd_en    = (h_counter<HFP)&&(h_counter>=HBP)&&(v_counter<VFP)&&(v_counter>=VBP);
wire   next_frm_rdy  = (v_counter>=VFP)&&(~disp_empty);
assign disp_rd_en    = (data_rd_en||next_frm_rdy);   //video channel 0
//--------------------------------------------------------
reg data_rd_en_ff1;
reg[15:0] alphadout_ff1;
reg[23:0] menu_dout_ff1;
reg[23:0] disp_dout_ff1;
reg[8:0]  menu_alpha_ff1;
always@(posedge clk_vga) menu_alpha_ff1 <= (menu_alpha[7:0] < 8'h10)?(8'h10):(menu_alpha[7:0] + 1);
always@(posedge clk_vga) data_rd_en_ff1 <= data_rd_en; 
always@(posedge clk_vga) disp_dout_ff1  <= disp_dout[23:0]; 
always@(posedge clk_vga) menu_dout_ff1  <= menu_dout[23:0]; 
always@(posedge clk_vga) alphadout_ff1  <= menu_dout[31:24] * menu_alpha_ff1; 
//--------------------------------------------------------
wire[7:0] real_alpha = alphadout_ff1[15:8];
//--------------------------------------------------------
reg       in_disp_area;
reg[8:0]  alpha1_data;  //fornt color
reg[8:0]  alpha0_data;  //backgroud color
reg[23:0] video_data;
reg[23:0] rgb_mask_data;
//--------------------------------------------------------
reg  bar_enable;
reg  in_bar;
//--------------------------------------------------------
always @(posedge clk_vga)  bar_enable <= ~mm_bar_hide;  
//--------------------------------------------------------
always @(posedge clk_vga,posedge rst) begin
    if(rst)begin 
        in_bar <= 1'b0;        
    end 
    else if((bar_enable)&&
            (v_counter > (VBP + 422))&&
            (v_counter < (VBP + 476))&&
            (h_counter < (HBP + 633))&&
            (h_counter > (HBP + 7))
            ) begin    
        in_bar <= 1'b1;        
    end 
    else begin
        in_bar <= 1'b0;        
    end
end 
//--------------------------------------------------------
localparam TICK_PERIOD = 400000;
//--------------------------------------------------------
reg[31:0] tick_cntr;
//--------------------------------------------------------
always@(posedge clk_vga,posedge rst) begin
    if(rst)begin 
        tick_cntr <= 32'b0;        
    end 
    else if(tick_cntr >= TICK_PERIOD)begin //10ms per tick
        tick_cntr <= 32'b0;        
    end    
    else if(bar_enable) begin
        tick_cntr <= tick_cntr + 32'b1;        
    end
end
//--------------------------------------------------------
reg[11:0] bar_fill;
//--------------------------------------------------------
always@(posedge clk_vga,posedge rst) begin
    if(rst)begin 
        bar_fill  <= 12'h0;
    end 
    else if(tick_cntr >= TICK_PERIOD)begin
        bar_fill  <= bar_fill + 12'h1;
    end 
end 
//--------------------------------------------------------
wire[23:0] gray_mask = {disp_graym[7:0],disp_graym[7:0],disp_graym[7:0]};
//--------------------------------------------------------
always@(posedge clk_vga) in_disp_area  <= data_rd_en_ff1; 
always@(posedge clk_vga) alpha0_data   <= mm_menu_en?(9'h100 - real_alpha):9'h100;
always@(posedge clk_vga) alpha1_data   <= mm_menu_en?(real_alpha + 1):9'h1;
always@(posedge clk_vga) video_data    <= disp_dout_ff1;//&gray_mask;
always@(posedge clk_vga) rgb_mask_data <= menu_dout_ff1;
//--------------------------------------------------------
reg[15:0] r_raw_data0;
reg[15:0] g_raw_data0;
reg[15:0] b_raw_data0;
reg[15:0] r_raw_data1;
reg[15:0] g_raw_data1;
reg[15:0] b_raw_data1;
//--------------------------------------------------------
always @(posedge clk_vga,posedge rst) begin
    if(rst)begin 
        r_raw_data0 <= 16'h0;
        g_raw_data0 <= 16'h0;
        b_raw_data0 <= 16'h0;         
        r_raw_data1 <= 16'h0;
        g_raw_data1 <= 16'h0;
        b_raw_data1 <= 16'h0;
    end 
    else if(in_disp_area)begin 
        if(bar_enable&in_bar) begin
            b_raw_data0 <= (h_counter < bar_fill)?16'h8800:16'h0;
            g_raw_data0 <= (h_counter < bar_fill)?16'hff00:16'h0;
            r_raw_data0 <= 16'h0;        
            b_raw_data1 <= 16'h0;
            g_raw_data1 <= 16'h0;
            r_raw_data1 <= 16'h0;
        end
        else begin
            b_raw_data0 <= video_data[7:0]*alpha0_data;
            g_raw_data0 <= video_data[15:8]*alpha0_data;
            r_raw_data0 <= video_data[23:16]*alpha0_data;        
            b_raw_data1 <= rgb_mask_data[7:0]*alpha1_data;
            g_raw_data1 <= rgb_mask_data[15:8]*alpha1_data;
            r_raw_data1 <= rgb_mask_data[23:16]*alpha1_data;                
        end    
    end 
    else begin
        r_raw_data0 <= 16'h0;
        g_raw_data0 <= 16'h0;
        b_raw_data0 <= 16'h0;         
        r_raw_data1 <= 16'h0;
        g_raw_data1 <= 16'h0;
        b_raw_data1 <= 16'h0;
    end
end 
//--------------------------------------------------------
reg[15:0] r_raw_show;
reg[15:0] g_raw_show;
reg[15:0] b_raw_show;    
//--------------------------------------------------------
always @(posedge clk_vga,posedge rst) begin
    if(rst)begin 
        r_raw_show <= 17'h0;
        g_raw_show <= 17'h0;
        b_raw_show <= 17'h0;            
    end 
    else begin 
        r_raw_show <= r_raw_data1 + r_raw_data0 ;
        g_raw_show <= g_raw_data1 + g_raw_data0 ;
        b_raw_show <= b_raw_data1 + b_raw_data0 ;              
    end 
end 
//--------------------------------------------------------
// delay 5 cycle  
reg[3:0] h_sync_ff;
reg[3:0] v_sync_ff;
reg[3:0] vga_de_ff;
always@(posedge clk_vga) h_sync_ff <= {h_sync_ff[2:0],h_sync};
always@(posedge clk_vga) v_sync_ff <= {v_sync_ff[2:0],v_sync};   
always@(posedge clk_vga) vga_de_ff <= {vga_de_ff[2:0],in_disp_area};   
//--------------------------------------------------------
always @(posedge clk_vga,posedge rst) begin
    if(rst)begin 
        vga_R <= 8'h0;
        vga_G <= 8'h0;
        vga_B <= 8'h0;            
    end 
    else begin 
        vga_R <= r_raw_show[15:8];
        vga_G <= g_raw_show[15:8];
        vga_B <= b_raw_show[15:8];              
    end 
end 
//--------------------------------------------------------
always @(posedge clk_vga,posedge rst) begin
    if(rst)begin 
        vga_h_sync <= 1'b0;
        vga_v_sync <= 1'b0;
        vga_de     <= 1'b0;            
    end 
    else begin 
        vga_h_sync <= h_sync_ff[3];
        vga_v_sync <= v_sync_ff[3];
        vga_de     <= vga_de_ff[1];            
    end 
end 
//--------------------------------------------------------
assign vga_pclk   = clk_vga;
// User logic ends

endmodule
